#include "ThreadPool.h"
#include<thread>
#include<memory>

const int TASK_MAX_THRESHOLD = 4;
const int THREAD_MAX_THRESHOLD = 10;
const int THREAD_MAX_IDLE_TIME = 10;  // 单位：秒

ThreadPool::ThreadPool()
	:initThreadSize_(0),
	taskSize_(0),
	idleThreadSize_(0),
	curThreadSize_(0),
	taskQueMaxThreshold_(TASK_MAX_THRESHOLD),
	threadSizeThreshold_(THREAD_MAX_THRESHOLD),
	poolMode_(PoolMode::MODE_FIXED),
	isPoolRunning_(false)
{}

ThreadPool::~ThreadPool()
{
	isPoolRunning_ = false;
	// 等待线程池中所有线程回收
	std::unique_lock<std::mutex> lock(taskQueMtx_);
	notEmpty_.notify_all();  // 唤醒所有线程
	exitCond_.wait(lock, [&]()->bool {return threads_.size() == 0; });
}

void ThreadPool::setMode(PoolMode mode)
{
	if (checkRunningState())//如果线程池已经启动，不可设置模式
		return;
	poolMode_ = mode;
}

void ThreadPool::setInitThreadSize(size_t size)
{
	initThreadSize_ = size;
}

void ThreadPool::setTaskQueMaxThreshHold(int threshhold)
{
	if (checkRunningState())
		return;
	taskQueMaxThreshold_ = threshhold;
}

void ThreadPool::setThreadSizeThreshold(int threshold)
{
	if (checkRunningState())
		return;
	if (poolMode_ == PoolMode::MODE_CACHED)
	{
		threadSizeThreshold_ = threshold;
	}
}


void ThreadPool::start(int initThreadSize)
{
	
	isPoolRunning_ = true;  // 设置线程池启动状态
	initThreadSize_ = initThreadSize;  // 初始线程个数
	curThreadSize_ = initThreadSize;
	
	// 创建线程对象
	for (int i = 0; i < initThreadSize_; ++i)
	{
		auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1));
		int threadId = ptr->getId();
		threads_.emplace(threadId, std::move(ptr));
	}

	// 启动初始所有线程
	for (int i = 0; i < initThreadSize_; ++i)
	{
		threads_[i]->start();
		idleThreadSize_++;  // 记录空闲线程数量
	}
}
// 线程函数
void ThreadPool::threadFunc(int threadid)
{
	auto lastTime = std::chrono::high_resolution_clock().now();
	while (1)
	{
		std::function<void()> task;
		{
			// 先获取锁
			std::unique_lock<std::mutex> lock(taskQueMtx_);

			std::cout << "id" << std::this_thread::get_id() << " 尝试获取任务..." << std::endl;
			
			// 无任务时：线程池运行，阻塞线程，线程池终止，回收线程
			while (taskQue_.size() == 0)
			{
				if (!isPoolRunning_) // 线程池终止，无任务，回收线程
				{
					// 回收线程
					threads_.erase(threadid);
					curThreadSize_--;

					std::cout << "threadid: " << std::this_thread::get_id()
						<< "  exit!" << std::endl;
					exitCond_.notify_all();
					return;
				}
				// cached模式，任务队列为空：超时回收线程，未超时阻塞线程
				if (poolMode_ == PoolMode::MODE_CACHED)
				{
					// 判断是超时被唤醒，还是被唤醒执行任务，如果是超时唤醒，就回收当前线程
					if (std::cv_status::timeout ==
						notEmpty_.wait_for(lock, std::chrono::seconds(1)))
					{
						auto now = std::chrono::high_resolution_clock().now();
						auto dur = std::chrono::duration_cast<std::chrono::seconds>(now - lastTime);
						if (dur.count() >= THREAD_MAX_IDLE_TIME
							&& curThreadSize_ > initThreadSize_)
						{
							// 回收当前线程：
							threads_.erase(threadid);
							curThreadSize_--;
							idleThreadSize_--;

							std::cout << "threadid: " << std::this_thread::get_id()
								<< "  exit!" << std::endl;
							return;
						}
					}
				}
				else  // fixed模式，任务队列为空：阻塞线程
				{
					notEmpty_.wait(lock);
				}
			}
			
			// 从任务队列中取任务出来
			task = taskQue_.front();
			taskQue_.pop();
			taskSize_--;
			idleThreadSize_--;  // 此线程已经执行任务，空闲线程-1
			std::cout << "id" << std::this_thread::get_id() << " 获取任务成功！" << std::endl;
			// 取出任务后，如果依然有剩余任务，通知其他线程继续执行任务
			if (taskQue_.size() > 0)
			{
				notEmpty_.notify_all();
			}

			// 取出一个任务后，任务队列必然不满，通知可以进行生产任务
			notFull_.notify_all();
		}// 释放锁
		
		
		// 当前线程负责执行这个任务
		if (task != nullptr)
		{
			task();
		}

		idleThreadSize_++;  // 此时任务执行完成，此线程空闲
		lastTime = std::chrono::high_resolution_clock().now();   // 更新lastTime为线程上一次执行完任务的时间
	}
	
}

bool ThreadPool::checkRunningState() const
{
	return isPoolRunning_;
}

// Thread

int Thread::generateId_ = 0; // 通过generateId_++ 来生成threadId_

Thread::Thread(ThreadFunc func)
	:func_(func)
	,threadId_(generateId_++)
{}

Thread::~Thread()
{
}
 
void Thread::start()
{	// 创建线程并启动线程函数
	std::thread t(func_, threadId_);
	t.detach(); // 设置分离线程
}

int Thread::getId() const
{
	return threadId_;
}

